/**
 * Copyright (C),2011-2012,北京国电通网络技术有限公司.
 * FileName:	downLoop.cpp
 * Author:		LiuHaifeng
 * Version:		V0.1
 * Date:		2011-11-15
 * Description	This file receives data from webservice, and put them in list by some fixed format, in order to dispose
 */
/**
 * History:
 * 		Author		date		Version		Description
 * 	  LiuHaifeng  2012-02-10	  V0.3      add alarm module
 */

#include "downLoop.h"
#include "../sqlite/sqlite.h"

extern struct StDataTransmit g_dataTrans;
extern struct StDownTask g_downTask;
extern struct StOther g_other;
extern struct StDeadTimeTask g_deadTimeTask;
extern struct StEquipList g_devList;
extern struct StUpTask g_upTask;
static int downLoopInit();
static void listTimeTask();
static int getSecondNow();
static int disposeData(char *);
static int insertCmdSt(char*,int);
static int rightFormat(char*);
static int wtimes;
static int flag_timeBefore;
static int flag_timeNow;
static int flag_clearFlag;
extern int flagAddress;                                ///flagAddress=0 set time;
extern bool upGradeKit;                               ///up grade flag

extern int optTimes;
extern int optBegin_time;

/***downLoopHandler() brief loop control down-stream dispose
 * param void
 *
 * retval,void
 ***/
void downLoopHandler(void)
{ 
	char l_tempStr[16];
	PRINTOUT("%s","in downLoopHandler()");
	if(-1==downLoopInit())
	{
		ERROROUT("downLoopInit() failed!");
		exit(1);
	}
	flag_clearFlag=0;
	flag_timeBefore=0;
    flag_timeNow=0;
    wtimes=0;
	int l_sendNum=0;
	int l_head;
	int recvDate_NUM;

    while(1)
    {
    START:
    	///upgrade
		if (isUpGrade())
		{
			setUpRespond();
			upGradeKit=true;
			goto UPGRADE00;
		}
		else
		{
			upGradeKit=false;
		}
    	/* 2012-02-10 V0.3 modify by LiuHaifeng begin */
		///alarm
		l_sendNum=0;
    	sem_wait(&(g_upTask.st_safeguardList.st_sem));///!!!!!
    	l_head=g_upTask.st_safeguardList.head;
    	while(l_head!=NO_MORE)
		{
			if (g_upTask.st_recvData[l_head].data.safeGuard.sendFlag==true)
			{
				///set flag
				if (isClear())
				{
					setBEAlarm();
					//send to mem									//set mem flag: lock
					g_other.st_pCmdOther=&g_other.st_shmADDR[1];
					recvDate_NUM=strlen((char*)g_upTask.st_recvData[l_head].data.safeGuard.safeguardAddr);
					g_other.st_pCmdOther[l_sendNum++]='#';
					for (int j=0;j<recvDate_NUM;j++)
					{
						sprintf(l_tempStr,"%02x",g_upTask.st_recvData[l_head].data.safeGuard.safeguardAddr[j]);
						g_other.st_pCmdOther[l_sendNum++]=l_tempStr[0];
						g_other.st_pCmdOther[l_sendNum++]=l_tempStr[1];
					}
					g_other.st_pCmdOther[l_sendNum++]='#';
					g_other.st_pCmdOther[l_sendNum++]='\0';
					l_sendNum=0;
					setAlarm();
					myDelay(20);
					if (isAlarm())
					{
						clearFlag();
					}
					else
					{
						g_upTask.st_recvData[l_head].data.safeGuard.sendFlag=false;
					}
				}
				l_head=g_upTask.st_recvData[l_head].next;
			}
			else
			{
				struct timeval l_tv;
				if(gettimeofday(&l_tv,NULL)==-1)
				{
					ERROROUT("get-time failed!");
				}
				if((l_tv.tv_sec-g_upTask.st_recvData[l_head].data.safeGuard.time)>ALARMTIME)
				{
					sem_wait(&(g_upTask.st_emtpy.st_sem));///!!!!!
					if(-1==removeElem(g_upTask.st_safeguardList,l_head))
						ERROROUT("delete device from memory failed!");
					l_head=g_upTask.st_safeguardList.head;
					sem_post(&(g_upTask.st_emtpy.st_sem));///!!!!!
				}
				if (l_head!=NO_MORE)
					l_head=g_upTask.st_recvData[l_head].next;
			}
		}
		sem_post(&(g_upTask.st_safeguardList.st_sem));///!!!!!
		/* 2012-02-10 V0.3 modify by LiuHaifeng end */
		///set time flag for socket
		if (flagAddress==0 && isClear())
		{
			setTimeFlag();
			myDelay(30);                                         ///sleep 30ms for socket detect markers
			if (isTimeFlag())
			{
				clearFlag();
			}
			else
			{
				flagAddress=-1;
			}
		}
		///judge flag
		if (flag_clearFlag==g_other.st_shmADDR[0])
		{
			flag_timeNow=getSecondNow();
			if (flag_clearFlag!=0 && flagAddress!=0 && (flag_timeNow-flag_timeBefore) >6)           ///6s
			{
				clearFlag();
			}
		}
		else
		{
			flag_clearFlag=g_other.st_shmADDR[0];
			flag_timeBefore=getSecondNow();
		}
		///operation status
		if(optTimes!=0 && (getSecondNow()-optBegin_time)>3 && isClear())
		{
			setOptStatus();
			myDelay(30);                                         ///sleep 30ms for socket detect markers
			if (!isOptStatus())
			{
				optTimes=0;
			}
		}
		///listTimeTask
		if(!isSet() || inDispose())
		{
			myDelay(10);					///sleep 100 ms
			if(wtimes<100)
				wtimes++;
			else
			{
				wtimes=0;
				listTimeTask();			///list time-task into 'g_downTask.st_task'
			}
		continue;
		}
		///see if have fill command
	UPGRADE00:
		while(!isCMDFlag())
		{
			if (isClear() && upGradeKit==true)
				goto START;
		}
		///see if have right format
		if(-1==rightFormat(&g_other.st_shmADDR[1]))
		{
			ERROROUT("error cmd format!");
			continue;
		}
		///operate command
		if(-1==disposeData(&g_other.st_shmADDR[1]))
		{
			ERROROUT("dipose cmd failed!");
			continue;
		}
		///if not require result, clear flag
		if(noRES())
		{
			clearFlag();
		}
		else
		{
			dispose();						///in dispose
		}
		///after dispose, sleep
		myDelay(5);

		///up grade dispose
		if (upGradeKit==true)
			goto UPGRADE00;
	}

	return;
}
/***disposeData() brief dispose received-data from webservice
 * param cmd[in], received data from webservice
 *
 * retval, 0 if successful or -1 failed.
 ***/
static int disposeData(char *cmd)
{
	int l_position=-1;									///'StControlCmd' position in array

	sem_wait(&g_downTask.st_emtpy.st_sem);///!!!!!
	l_position=getElem(g_downTask.st_emtpy);			///apply 'StControlCmd' to store command
	sem_post(&g_downTask.st_emtpy.st_sem);///!!!!!
	if(-1==l_position)
	{
		ERROROUT("no enought 'StControlCmd'!");
		sendService(err_memory);
		return -1;
	}
	if(-1==insertCmdSt(cmd,l_position))
	{
		ERROROUT("insertCmdSt() failed!");
		goto Error;
	}
	else
	{
		sem_wait(&g_downTask.st_task.st_sem);///!!!!!!
		insertElem(g_downTask.st_task,l_position);
		sem_post(&g_downTask.st_task.st_sem);///!!!!!!
	}

	return 0;

	Error:
	memset(&g_downTask.st_command[l_position],0,sizeof(struct StControlCmd));
	sem_wait(&g_downTask.st_emtpy.st_sem);///!!!!!!
	insertElem(g_downTask.st_emtpy,l_position);
	sem_post(&g_downTask.st_emtpy.st_sem);///!!!!!!
	return -1;
}
/***insertCmdSt() brief translate the received data to struct 'StControlCmd'
 * 	param pcmd[in], pointer to data read from webservice
 *  param position[in], position of struct 'StControlCmd' which save data formated in command.
 *
 * 	retval int, 0 is plain task, 1 mode task, -1 if failed
 ***/
static int insertCmdSt(char* pcmd,int position)
{
	int l_tmpTime;
	///command format"#factoryID deviceID numberID 0000#cmdType#var1 var2#varType#value#"
	pcmd++;												///the first is '#'
	///pcmdSt->typeID[0]---factoryID
	g_downTask.st_command[position].typeID[0]=charToUnsigned(&pcmd);
	///pcmdSt->typeID[1]---deviceID
	g_downTask.st_command[position].typeID[1]=charToUnsigned(&pcmd);
	///pcmdSt->typeID[2]---numberID
	g_downTask.st_command[position].typeID[2]=charToUnsigned(&pcmd);
    ///homeID
	pcmd++;
	pcmd++;
	pcmd++;
	pcmd++;
	if('#'!=*pcmd)
		goto FormatError;
	pcmd++;
	///pcmdSt->cmdType
	g_downTask.st_command[position].cmdType=charToUnsigned(&pcmd);
	if('#'!=*pcmd)
		goto FormatError;
	pcmd++;
	///pcmdSt->param[0]
	g_downTask.st_command[position].param[0]=charToUnsigned(&pcmd);
	///pcmdSt->param[1]
	g_downTask.st_command[position].param[1]=charToUnsigned(&pcmd);
	if('#'!=*pcmd)
		goto FormatError;
	pcmd++;
	///pcmdSt->varType
	g_downTask.st_command[position].otherParam=charToUnsigned(&pcmd);
	///change pcmdSt->varType=0x8x
	pcmd=pcmd-2;
	*pcmd='8';
	pcmd+=2;
	pcmd++;										///discard '#',pcmd point to 变参第一个字符
	g_other.st_pCmdOther=pcmd;					///point to other variables

	///all up change is true???
	if(false==g_other.st_charToUnsignedFlag)
	{
		g_other.st_charToUnsignedFlag=true;
		goto FormatError;
	}
	///priority
	if(0x01==g_downTask.st_command[position].cmdType && 0xfe==g_downTask.st_command[position].param[0] && 0==g_downTask.st_command[position].otherParam)///if command is mode task to be operated
		g_downTask.st_command[position].priority=prio_modeltask;
	else
		g_downTask.st_command[position].priority=prio_nomal;


	if(g_downTask.st_command[position].otherParam>0)
	{
		if(0x01==g_downTask.st_command[position].cmdType && 0x01==g_downTask.st_command[position].otherParam)		///time task
		{
			char l_tempStr[12];													///temporary char array
			struct timeval l_tv;												///time stamp

			memcpy(l_tempStr,pcmd+2,10);										///frequency+timestamp, skip frequency get timestamp
			l_tempStr[10]='\0';
			g_downTask.st_command[position].controlTime=atoi(l_tempStr);

			///save in memory
			if(gettimeofday(&l_tv,NULL)==-1)
			{
				ERROROUT("gettimeofday() failed!");
				sendService(err_other);
				return -1;
			}
			if(g_downTask.st_command[position].controlTime<=l_tv.tv_sec)		///if outdate, just ignore
				goto FormatError;
			///adjust time stamp
			l_tmpTime=getTodayZero(l_tv.tv_sec);
			if(g_downTask.st_command[position].controlTime > l_tv.tv_sec && g_downTask.st_command[position].controlTime <= (l_tmpTime+3600*24))
			{
				int l_pos=-1;
				sem_wait(&g_downTask.st_emtpy.st_sem);///!!!!!
				l_pos=getElem(g_downTask.st_emtpy);
				sem_post(&g_downTask.st_emtpy.st_sem);///!!!!!
				if(-1==l_pos)
				{
					ERROROUT("no enought StControlCmd!");
					sendService(err_memory);
					return -1;
				}
				g_downTask.st_command[l_pos].typeID[0]=g_downTask.st_command[position].typeID[0];
				g_downTask.st_command[l_pos].typeID[1]=g_downTask.st_command[position].typeID[1];
				g_downTask.st_command[l_pos].typeID[2]=g_downTask.st_command[position].typeID[2];
				g_downTask.st_command[l_pos].cmdType=g_downTask.st_command[position].cmdType;
				g_downTask.st_command[l_pos].param[0]=g_downTask.st_command[position].param[0];
				g_downTask.st_command[l_pos].param[1]=g_downTask.st_command[position].param[1];
				g_downTask.st_command[l_pos].otherParam=0;
				g_downTask.st_command[l_pos].controlTime=g_downTask.st_command[position].controlTime;
				g_downTask.st_command[l_pos].priority=prio_timetask;
				sem_wait(&g_downTask.st_timeTask.st_sem);///!!!!!
				insertElem(g_downTask.st_timeTask,l_pos);
				sem_post(&g_downTask.st_timeTask.st_sem);///!!!!!
			}
		}
	}

	return 0;

	FormatError:
		sendService(err_format);
		return -1;
}
/***listTimeTask() brief dispose the deadtimetask and timetask period
 * 	param void, null
 *
 * 	retval int, 0 if sucessful -1 if failed
 ***/
void listTimeTask()
{
	struct timeval l_tv;
	if(-1==gettimeofday(&l_tv,NULL))
	{
		ERROROUT("listTimeTask get-time failed!");
		return;
	}
	
	//////list deadTimeTask
	///synchronous time-task everyday's 00:00
	if(g_deadTimeTask.st_syncTimeTask<= l_tv.tv_sec)
	{
		if(-1==updateTask00())
		{
			ERROROUT("synchronous time-task failed");
			///continue;
		}
		else
		{
			PRINTOUT("%d",l_tv.tv_sec);
			PRINTOUT("%d",g_deadTimeTask.st_syncTimeTask);
			int temp;
			temp = getTodayZero(l_tv.tv_sec);
			PRINTOUT("%d",temp);
			PRINTOUT("%s","synchronous time-task in 00:00!");
			g_deadTimeTask.st_syncTimeTask+=3600*24;
		}
	}
	///inquiry total-elec
	if(g_deadTimeTask.st_inquiryElec<= l_tv.tv_sec)
	{
		int l_devPos=g_devList.st_equip.head;
		int l_comPos;
		for(;l_devPos!=-1;l_devPos=g_devList.st_equipArray[l_devPos].next)
		{
			if(g_devList.st_equipArray[l_devPos].elecQueryStatus==sta_have || ((g_devList.st_equipArray[l_devPos].typeID >> 12 & 0xf) == 0xf))
				continue;///make sure no inquiry or not safeguard
			g_devList.st_equipArray[l_devPos].elecQueryStatus=sta_have;
			break;
		}
		if(-1==l_devPos)			///if all devices have been inquiried or no device at all
		{
			l_devPos=g_devList.st_equip.head;
			for(;l_devPos!=-1;l_devPos=g_devList.st_equipArray[l_devPos].next)
				g_devList.st_equipArray[l_devPos].elecQueryStatus=sta_no;
			g_deadTimeTask.st_inquiryElec += ELECGETINTERVAL;
		}
		else						///if have device
		{
			sem_wait(&g_downTask.st_emtpy.st_sem);///!!!!!!
			l_comPos=getElem(g_downTask.st_emtpy);
			sem_post(&g_downTask.st_emtpy.st_sem);///!!!!!!
			if(-1==l_comPos)
			{
				ERROROUT("no enough 'struct StControlCmd' for deadTimeTask!");
				return;
			}
			g_downTask.st_command[l_comPos].typeID[0]=g_devList.st_equipArray[l_devPos].typeID>>16 & 0xff;
			g_downTask.st_command[l_comPos].typeID[1]=g_devList.st_equipArray[l_devPos].typeID>>8 & 0xff;
			g_downTask.st_command[l_comPos].typeID[2]=g_devList.st_equipArray[l_devPos].typeID & 0xff;
			g_downTask.st_command[l_comPos].param[0]=0xfd;							///var1=0xfd
			g_downTask.st_command[l_comPos].param[1]=0x01;							///no var2
			g_downTask.st_command[l_comPos].cmdType=0x02;							///inquiry command
			g_downTask.st_command[l_comPos].otherParam=0;							///no other-var
			g_downTask.st_command[l_comPos].priority=prio_inquiryElec;				///prio_inquiryElec priority
			sem_wait(&g_downTask.st_task.st_sem);///!!!!!!
			insertElem(g_downTask.st_task,l_comPos);
			sem_post(&g_downTask.st_task.st_sem);///!!!!!!
		}
	}
	///inquiry active power
	if(g_deadTimeTask.st_inquiryYGGL<= l_tv.tv_sec)
	{
		int l_devPos=g_devList.st_equip.head;
		int l_comPos;
		for(;l_devPos!=-1;l_devPos=g_devList.st_equipArray[l_devPos].next)
		{
			if(g_devList.st_equipArray[l_devPos].activeQueryStatus==sta_have || ((g_devList.st_equipArray[l_devPos].typeID >> 12 & 0xf) == 0xf))
				continue;///make sure no inquiry or not safeguard
			g_devList.st_equipArray[l_devPos].activeQueryStatus=sta_have;
			break;
		}
		if(-1==l_devPos)			///if all devices have been inquiried or no device at all
		{
			l_devPos=g_devList.st_equip.head;
			for(;l_devPos!=-1;l_devPos=g_devList.st_equipArray[l_devPos].next)
				g_devList.st_equipArray[l_devPos].activeQueryStatus=sta_no;
			g_deadTimeTask.st_inquiryYGGL += YGGLGETINTERVAL;
		}
		else						///if have device
		{
			sem_wait(&g_downTask.st_emtpy.st_sem);///!!!!!!
			l_comPos=getElem(g_downTask.st_emtpy);
			sem_post(&g_downTask.st_emtpy.st_sem);///!!!!!!
			if(-1==l_comPos)
			{
				ERROROUT("no enough 'struct StControlCmd' for deadTimeTask!");
				return;
			}
			g_downTask.st_command[l_comPos].typeID[0]=g_devList.st_equipArray[l_devPos].typeID>>16 & 0xff;
			g_downTask.st_command[l_comPos].typeID[1]=g_devList.st_equipArray[l_devPos].typeID>>8 & 0xff;
			g_downTask.st_command[l_comPos].typeID[2]=g_devList.st_equipArray[l_devPos].typeID & 0xff;
			g_downTask.st_command[l_comPos].param[0]=0xfb;							///var1=0xfb
			g_downTask.st_command[l_comPos].param[1]=0x01;							///var2=0x01
			g_downTask.st_command[l_comPos].cmdType=0x02;							///inquiry command
			g_downTask.st_command[l_comPos].otherParam=0;							///no other-var
			g_downTask.st_command[l_comPos].priority=prio_inquiryElec;				///prio_nomal priority
			sem_wait(&g_downTask.st_task.st_sem);///!!!!!!
			insertElem(g_downTask.st_task,l_comPos);
			sem_post(&g_downTask.st_task.st_sem);///!!!!!!
		}
	}
	//////list timeTask
	sem_wait(&g_downTask.st_timeTask.st_sem);///!!!!!!
	for(int i=g_downTask.st_timeTask.head;i!=-1;)
	{
		if(g_downTask.st_command[i].controlTime<=l_tv.tv_sec)
		{
			g_downTask.st_command[i].controlTime=0;
			getElem(g_downTask.st_timeTask);
			sem_wait(&g_downTask.st_task.st_sem);///!!!!!!
			insertElem(g_downTask.st_task,i);
			sem_post(&g_downTask.st_task.st_sem);///!!!!!!
			i=g_downTask.st_timeTask.head;
		}
		else
			i=g_downTask.st_command[i].next;
	}
	sem_post(&g_downTask.st_timeTask.st_sem);///!!!!!!
}
/***downLoopInit() brief initialize function
 * param	null
 *
 * retval  	0 if successful or -1 if failed.
 ***/
static int downLoopInit()
{
	PRINTOUT("%s","in downLoopInit()");

	return 0;
}

/***getSecondNow() get second
 * param null
 *
 *retval secondtime
 ***/
static int getSecondNow()
{
	struct timeval l_tv;
	if(gettimeofday(&l_tv,NULL)==-1)
	{
		ERROROUT("gettimeofday() failed!");
	}

	return l_tv.tv_sec;
}
/***rightFormat() brief see if received data have right format
 * 	param pcmd[in], pointer to data read from webservice
 *
 * 	retval int, 0 is right, -1 wrong wrong format
 ***/
static int rightFormat(char* pcmd)
{
	///test command format---length-head-tail---make sure the first char is '#'
	PRINTOUT("%s",pcmd);
	if(strlen(pcmd)<CMD_LENGTH_MIN || pcmd[0]!='#' || pcmd[CMD_LENGTH_MIN-1]!='#')
		goto ERROR;
	///return
	return 0;

	ERROR:
	sendService(err_format);
	return -1;
}
